#include "OpenGLGraphicWindow.h"
#include "WindowEventManager.h"
namespace Render
{
	rtOpenGLGraphicWindow::rtOpenGLGraphicWindow(void):
    _hWnd(NULL),
	_hGLRC(NULL),
	_hDC(NULL),
	_windowClassRegistered(false)
	{
		_hInstance = ::GetModuleHandle(NULL);
	}


	rtOpenGLGraphicWindow::~rtOpenGLGraphicWindow(void)
	{
		destroy();
	}



	bool rtOpenGLGraphicWindow::init(std::string& windowName, rtWindowInfo& createInfo)
	{
		_windowName = windowName;
		_windowInfo = createInfo;

		HDC		hDC;

		hDC = GetDC( GetDesktopWindow() );
		_desktopBitsPixel = GetDeviceCaps(hDC, BITSPIXEL);
		_desktopWidth = GetDeviceCaps(hDC, HORZRES);
		_desktopHeight = GetDeviceCaps(hDC, VERTRES);
		ReleaseDC(GetDesktopWindow(), hDC);

		if (_desktopBitsPixel < 32 && !createInfo.fullScreen) 
		{
			return false;
		}

		registerWindowClasses();

		if(_windowInfo.fullScreen)
		{
			if(!setFullScreen())
			{
				destroy();
				return false;
			}
		}

		if (!createWindow())
		{
			destroy();
			return false;
		}

		return true;
	}

	void rtOpenGLGraphicWindow::registerWindowClasses(void) 
	{
		WNDCLASS wc;
		if (_windowClassRegistered ) 
		{
			return;
		}

		memset( &wc, 0, sizeof( wc ) );

		wc.style         = 0;
		wc.lpfnWndProc   = (WNDPROC) rtWindowEventManager::MainWndProc;
		wc.cbClsExtra    = 0;
		wc.cbWndExtra    = 0;
		wc.hInstance     = _hInstance;
		wc.hIcon         = LoadIcon( _hInstance, IDC_ICON);
		wc.hCursor       = LoadCursor (NULL,IDC_ARROW);
		wc.hbrBackground = (struct HBRUSH__ *)COLOR_GRAYTEXT;
		wc.lpszMenuName  = 0;
		wc.lpszClassName = _windowName.c_str();

		if ( !RegisterClass( &wc ) ) 
		{
			return;
		}


		_windowClassRegistered = true;
	}


	bool rtOpenGLGraphicWindow::setFullScreen() 
	{
		DEVMODE dm;
		int		cdsRet;

		DEVMODE		devmode;
		int			modeNum;
		bool		matched;

		matched = false;
		for ( modeNum = 0 ; ; modeNum++ ) 
		{
			if (!EnumDisplaySettings(NULL, modeNum, &devmode)) 
			{
				if (matched) 
				{
					_windowInfo.displayHz = 0;
					break;
				}
				return false;
			}
			if ((int)devmode.dmPelsWidth >= _windowInfo.width
				&& (int)devmode.dmPelsHeight >= _windowInfo.height
				&& devmode.dmBitsPerPel == 32) 
			{
					matched = true;
					if ( _windowInfo.displayHz == 0 || devmode.dmDisplayFrequency == _windowInfo.displayHz ) 
					{
						break;
					}
			}
		}

		memset( &dm, 0, sizeof( dm ) );
		dm.dmSize = sizeof( dm );

		dm.dmPelsWidth  = _windowInfo.width;
		dm.dmPelsHeight = _windowInfo.height;
		dm.dmBitsPerPel = 32;
		dm.dmFields     = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL;

		if ( _windowInfo.displayHz != 0 ) 
		{
			dm.dmDisplayFrequency = _windowInfo.displayHz;
			dm.dmFields |= DM_DISPLAYFREQUENCY;
		}

		if ( ( cdsRet = ChangeDisplaySettings( &dm, CDS_FULLSCREEN ) ) == DISP_CHANGE_SUCCESSFUL ) 
		{
			return true;
		}


		for ( modeNum = 0 ; ; modeNum++ ) 
		{
			if (!EnumDisplaySettings( NULL, modeNum, &devmode ) ) 
			{
				break;
			}
			if ((int)devmode.dmPelsWidth >= _windowInfo.width
				&& (int)devmode.dmPelsHeight >= _windowInfo.height
				&& devmode.dmBitsPerPel == 32) 
			{
				if ((cdsRet = ChangeDisplaySettings( &devmode, CDS_FULLSCREEN)) == DISP_CHANGE_SUCCESSFUL) 
				{
					return true;
				}
				break;
			}
		}

		return false;
	}


	bool rtOpenGLGraphicWindow::createWindow() 
	{
		int				stylebits;
		int				x, y, w, h;
		int				exstyle;

		if ( _windowInfo.fullScreen ) 
		{
			exstyle = WS_EX_TOPMOST;
			stylebits = WS_POPUP|WS_VISIBLE|WS_SYSMENU;

			x = 0;
			y = 0;
			w = _windowInfo.width;
			h = _windowInfo.height;
		} 
		else 
		{
			RECT	r;
			r.bottom = _windowInfo.height;
			r.left = 0;
			r.top = 0;
			r.right = _windowInfo.width;

			exstyle = 0;
			stylebits = WS_OVERLAPPED|WS_BORDER|WS_CAPTION|WS_VISIBLE | WS_THICKFRAME|WS_SYSMENU;
			AdjustWindowRect (&r, stylebits, FALSE);

			w = r.right - r.left;
			h = r.bottom - r.top;


			x = (_desktopWidth - w) / 2;
			y = (_desktopHeight - h) / 2;
		}

		_hWnd = CreateWindowEx (
			exstyle, 
			_windowName.c_str(),
			_windowName.c_str(),
			stylebits,
			x, y, w, h,
			NULL,
			NULL,
			_hInstance,
			NULL);

		if (_hWnd) 
		{
			return false;
		}

		::SetTimer(_hWnd, 0, 100, NULL );

		ShowWindow(_hWnd, SW_SHOW);
		UpdateWindow(_hWnd);

		if (!initDriver()) 
		{
			ShowWindow(_hWnd, SW_HIDE );
			DestroyWindow(_hWnd);
			_hWnd = NULL;
			return false;
		}

		SetForegroundWindow(_hWnd);
		SetFocus(_hWnd);
		return true;
	}


	bool rtOpenGLGraphicWindow::initDriver() 
	{
		PIXELFORMATDESCRIPTOR src = 
		{
			sizeof(PIXELFORMATDESCRIPTOR),	// size of this pfd
			1,								// version number
			PFD_DRAW_TO_WINDOW |			// support window
			PFD_SUPPORT_OPENGL |			// support OpenGL
			PFD_DOUBLEBUFFER,				// double buffered
			PFD_TYPE_RGBA,					// RGBA type
			32,								// 32-bit color depth
			0, 0, 0, 0, 0, 0,				// color bits ignored
			8,								// 8 bit destination alpha
			0,								// shift bit ignored
			0,								// no accumulation buffer
			0, 0, 0, 0, 					// accum bits ignored
			24,								// 24-bit z-buffer	
			8,								// 8-bit stencil buffer
			0,								// no auxiliary buffer
			PFD_MAIN_PLANE,					// main layer
			0,								// reserved
			0, 0, 0							// layer masks ignored
		};

		if (_hDC == NULL ) 
		{

			if ( (_hDC = GetDC( _hWnd) ) == NULL ) 
			{
				return false;
			}
		}

		if (_windowInfo.stereo) 
		{
			src.dwFlags |= PFD_STEREO;
		}

		

		if ((_pixelformat = ChoosePixelFormat(_hDC, &src)) == 0 ) 
		{
			return false;
		}

		DescribePixelFormat(_hDC, _pixelformat, sizeof(_pfd ), &_pfd);
		
		if ( SetPixelFormat(_hDC, _pixelformat, &_pfd) == FALSE ) 
		{
			return false;
		}

		if ((_hGLRC = wglCreateContext(_hDC )) == 0) 
		{
			return false;
		}

		if ( !wglMakeCurrent(_hDC, _hGLRC) ) {
			wglDeleteContext(_hGLRC);
			_hGLRC = NULL;
			return false;
		}

		return true;
	}

	void rtOpenGLGraphicWindow::destroy()
	{
		wglMakeCurrent( NULL, NULL );
		if ( _hGLRC ) 
		{
			wglDeleteContext(_hGLRC );
			_hGLRC = NULL;
		}
		 
		if ( _hDC ) 
		{
			ReleaseDC(_hWnd, _hDC );
			_hDC  = NULL;
		}

		if ( _hWnd ) 
		{

			ShowWindow(_hWnd, SW_HIDE );
			DestroyWindow( _hWnd );
			_hWnd = NULL;
		}
	}

}

